package frontend.pages.admin.employee;

import backend.model.admin.Occupation;
import backend.model.admin.Team;
import backend.model.other.User;
import shared.other.UserRolesDefinition;
import shared.other.UserRolesDefinition.UserRole;
import backend.service.admin.EmployeeService;
import backend.service.admin.OccupationService;
import backend.service.admin.TeamService;
import backend.service.other.UserService;
import frontend.core.TimeTrackingWebApplication;
import frontend.core.TimeTrackingWebSession;
import frontend.model.admin.EmployeeUIModel;
import frontend.pages.admin.base.AbstractManagingForm;
import frontend.components.base.ComponentFactory;
import frontend.components.other.DBModelChoiceRenderer;
import frontend.components.other.UserInputCallableAction;
import frontend.components.other.UserRoleChoiceRender;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class EmployeeForm extends AbstractManagingForm<EmployeeUIModel> {

    public static final String IDENTIFICATION_CARD_PREFIX = "HR";

    private static final String RESOURCE_KEY_FIELD_LABEL_FIRST_NAME = "pages.admin.employee.form.firstName";
    private static final String RESOURCE_KEY_FIELD_LABEL_LAST_NAME = "pages.admin.employee.form.lastName";
    private static final String RESOURCE_KEY_FIELD_LABEL_IDENTIFICATION_CARD = "pages.admin.employee.form.identificationCard";
    private static final String RESOURCE_KEY_FIELD_LABEL_OCCUPATION = "pages.admin.employee.form.occupation";
    private static final String RESOURCE_KEY_FIELD_LABEL_TEAM = "pages.admin.employee.form.team";
    private static final String RESOURCE_KEY_FIELD_LABEL_IS_ACTIVE = "pages.admin.employee.form.isActive";
    private static final String RESOURCE_KEY_FIELD_LABEL_USERNAME = "pages.admin.employee.form.username";
    private static final String RESOURCE_KEY_FIELD_LABEL_IS_APPLICATION_USER = "pages.admin.employee.form.isApplicationUser";
    private static final String RESOURCE_KEY_FIELD_LABEL_ROLE = "pages.admin.employee.form.role";
    private static final String RESOURCE_KEY_FIELD_LABEL_FOREMAN = "pages.admin.employee.form.isForeman";

    private static final String RESOURCE_KEY_VALIDATION_SAME_EMPLOYEE_NAME = "validation.form.employee.sameEmployeeName";
    private static final String RESOURCE_KEY_VALIDATION_SAME_IDENTIFICATION_CARD = "validation.form.employee.sameIdentificationCard";
    private static final String RESOURCE_KEY_VALIDATION_SAME_USERNAME = "validation.form.employee.sameUsername";
    private static final String RESOURCE_KEY_VALIDATION_NOT_STARTING_WITH_PREFIX = "validation.form.identificationCard.notStartingWithPrefix";
    private static final String RESOURCE_KEY_VALIDATION_TEAMS_ASSOCIATION = "validation.form.foreman.teamAssociation";

    private WebMarkupContainer applicationUserContainer;

    public EmployeeForm(String id, EmployeeUIModel employeeUIModel) {
		super(id, employeeUIModel);
        feedbackPanel.setFilter(new ContainerFeedbackMessageFilter(EmployeeForm.this));
	}

	@Override
	protected void constructFormContent() {
		WebMarkupContainer firstNameComponent = ComponentFactory.createTextFieldComponent("firstName", RESOURCE_KEY_FIELD_LABEL_FIRST_NAME, uiModel);
        WebMarkupContainer lastNameComponent = ComponentFactory.createTextFieldComponent("lastName", RESOURCE_KEY_FIELD_LABEL_LAST_NAME, uiModel);
        WebMarkupContainer identificationCardComponent = ComponentFactory.createTextFieldComponent("identificationCard", RESOURCE_KEY_FIELD_LABEL_IDENTIFICATION_CARD, uiModel);
        WebMarkupContainer occupationComponent = ComponentFactory.createDropDownChoiceComponent("occupation", RESOURCE_KEY_FIELD_LABEL_OCCUPATION, uiModel, getAvailableOccupations(), new DBModelChoiceRenderer<Occupation>(), false);
        WebMarkupContainer teamComponent = ComponentFactory.createDropDownChoiceComponent("team", RESOURCE_KEY_FIELD_LABEL_TEAM, uiModel, getAvailableTeams(), new DBModelChoiceRenderer<Team>(), false);
        WebMarkupContainer isForemanComponent = ComponentFactory.createCheckboxComponent("isForeman", RESOURCE_KEY_FIELD_LABEL_FOREMAN, uiModel);
        WebMarkupContainer isActiveComponent = ComponentFactory.createCheckboxComponent("isActive", RESOURCE_KEY_FIELD_LABEL_IS_ACTIVE, uiModel);

        applicationUserContainer = new WebMarkupContainer("applicationUserContainer");
        applicationUserContainer.setOutputMarkupId(true);
        applicationUserContainer.setEnabled(uiModel.getIsApplicationUser());
        WebMarkupContainer isApplicationUserComponent = ComponentFactory.createCheckboxComponent("isApplicationUser", RESOURCE_KEY_FIELD_LABEL_IS_APPLICATION_USER, uiModel, createIsApplicationUserValueChangedAction());
        WebMarkupContainer usernameComponent = ComponentFactory.createTextFieldComponent("username", RESOURCE_KEY_FIELD_LABEL_USERNAME, uiModel);
        WebMarkupContainer userRoleComponent = ComponentFactory.createDropDownChoiceComponent("role", RESOURCE_KEY_FIELD_LABEL_ROLE, uiModel, Arrays.asList(UserRole.values()), new UserRoleChoiceRender(), false);
        applicationUserContainer.add(usernameComponent, userRoleComponent);

        add(firstNameComponent, lastNameComponent, identificationCardComponent, occupationComponent, teamComponent, isForemanComponent, isActiveComponent,
                isApplicationUserComponent, applicationUserContainer);
	}

    private UserInputCallableAction<Boolean> createIsApplicationUserValueChangedAction() {
        return new UserInputCallableAction<Boolean>() {
            @Override
            public void call(AjaxRequestTarget target, Boolean selectedValue) {
                if (selectedValue) {
                    applicationUserContainer.setEnabled(true);
                } else {
                    applicationUserContainer.setEnabled(false);
                }
                target.add(applicationUserContainer);
            }
        };
    }

    @Override
    protected Class getResponsePage() {
        return EmployeeManagingPage.class;
    }

    @Override
    protected void doFormValidation() {
        validateNotEmpty(uiModel.getFirstName(), RESOURCE_KEY_FIELD_LABEL_FIRST_NAME);
        validateNotEmpty(uiModel.getLastName(), RESOURCE_KEY_FIELD_LABEL_LAST_NAME);
        validateNotEmpty(uiModel.getOccupation(), RESOURCE_KEY_FIELD_LABEL_OCCUPATION);
        validateNotEmpty(uiModel.getIdentificationCard(), RESOURCE_KEY_FIELD_LABEL_IDENTIFICATION_CARD);
        validateNotEmpty(uiModel.getTeam(), RESOURCE_KEY_FIELD_LABEL_TEAM);

        if (uiModel.getIdentificationCard() != null && false == uiModel.getIdentificationCard().toUpperCase().startsWith(IDENTIFICATION_CARD_PREFIX)) {
            addFieldValidationError(RESOURCE_KEY_FIELD_LABEL_IDENTIFICATION_CARD, RESOURCE_KEY_VALIDATION_NOT_STARTING_WITH_PREFIX);
        }

        if (uiModel.getIsApplicationUser()) {
            validateNotEmpty(uiModel.getUsername(), RESOURCE_KEY_FIELD_LABEL_USERNAME);
            validateNotEmpty(uiModel.getRole(), RESOURCE_KEY_FIELD_LABEL_ROLE);
        }

        EmployeeService employeeService = TimeTrackingWebApplication.getService(EmployeeService.class);
        if (uiModel.getFirstName() != null && uiModel.getLastName() != null && firstOrLastNameWasChanged()) {
            if (employeeService.findEmployeeByFirstAndLastName(uiModel.getFirstName(), uiModel.getLastName()) != null) {
                addGeneralValidationError(RESOURCE_KEY_VALIDATION_SAME_EMPLOYEE_NAME);
            }
        }

        if (uiModel.getIdentificationCard() != null && identificationCardWasChanged()) {
            if (employeeService.findActiveEmployeeByIdentificationCard(uiModel.getIdentificationCard()) != null) {
                addFieldValidationError(RESOURCE_KEY_FIELD_LABEL_IDENTIFICATION_CARD, RESOURCE_KEY_VALIDATION_SAME_IDENTIFICATION_CARD);
            }
        }

        if (uiModel.getFirstName() != null && uiModel.getLastName() != null && firstOrLastNameWasChanged()) {
            if (employeeService.findEmployeeByFirstAndLastName(uiModel.getFirstName(), uiModel.getLastName()) != null) {
                addGeneralValidationError(RESOURCE_KEY_VALIDATION_SAME_EMPLOYEE_NAME);
            }
        }

        UserService userService = TimeTrackingWebApplication.getService(UserService.class);
        if (uiModel.getUsername() != null && usernameWasChanged()) {
            if (userService.findUserByUsername(uiModel.getUsername()) != null) {
                addFieldValidationError(RESOURCE_KEY_FIELD_LABEL_USERNAME, RESOURCE_KEY_VALIDATION_SAME_USERNAME);
            }
        }

        if (isForemanFlagUnchecked()) {
            TeamService teamService = TimeTrackingWebApplication.getService(TeamService.class);
            List<Team> allTeamsOfForeman = teamService.findAllTeamsOfForeman(uiModel.getDBModel().getForeman().getId());
            if (allTeamsOfForeman.size() > 0) {
                StringResourceModel resourceModel = new StringResourceModel(RESOURCE_KEY_VALIDATION_TEAMS_ASSOCIATION, new Model<String>(allTeamsOfForeman.toString()));
                addFieldValidationErrorForAlreadyLocalizedMessage(RESOURCE_KEY_FIELD_LABEL_FOREMAN, resourceModel.getString());
            }
        }
    }

    private boolean firstOrLastNameWasChanged() {
        return (false == (uiModel.getFirstName() + uiModel.getLastName()).equals(
                uiModel.getDBModel().getFirstName() + uiModel.getDBModel().getLastName()));
    }

    private boolean identificationCardWasChanged() {
        return false == (uiModel.getIdentificationCard().toUpperCase().equals(uiModel.getDBModel().getIdentificationCard()));
    }

    private boolean isForemanFlagUnchecked() {
        return uiModel.getDBModel().getForeman() != null && uiModel.getIsForeman() == false;
    }

    private boolean usernameWasChanged() {
        User user = uiModel.getDBModel().getUser();
        return (user != null) && (false == (uiModel.getUsername().equals(user.getUsername())));
    }

    private List<Team> getAvailableTeams() {
        List<Team> availableTeams;
        TeamService teamService = TimeTrackingWebApplication.getService(TeamService.class);

        String loggedInUsername = (String) TimeTrackingWebSession.get().getAttribute(TimeTrackingWebSession.LOGIN_USERNAME_ATTR);
        User user = TimeTrackingWebApplication.getService(UserService.class).findUserByUsername(loggedInUsername);
        boolean isForeman = UserRolesDefinition.UserRole.FOREMAN.equals(user.getRole());

        if (isForeman) {
            availableTeams = teamService.findAllActiveTeamsOfForeman(user.getEmployee().getForeman().getId());
        } else {
            availableTeams = teamService.findAllTeams();
        }

        return availableTeams;
    }

    private List<Occupation> getAvailableOccupations() {
        List<Occupation> availableOccupations = new ArrayList<Occupation>();
        availableOccupations.addAll(TimeTrackingWebApplication.getService(OccupationService.class).findAllActiveOccupations());
        return availableOccupations;
    }
}
